
#ifndef __PAISLEYPARK__FACTORY_H__
#define __PAISLEYPARK__FACTORY_H__

#include <iostream>
#include <map>

class Shape {	
public:
	virtual void Draw() const = 0;
	virtual void Rotate(double angle) = 0;
	virtual void Zoom (double zoomFactor) = 0;
};

class Line : public Shape {
public:
	void Draw() const {
		std::cout << "draw line" << std::endl;
	};

	void Rotate(double angle) {
		std::cout << angle << std::endl;
	};

	void Zoom(double zoomFactor) {
		std::cout << zoomFactor << std::endl;
	};
};

class Drawing {
public:
	void Save(std::ofstream& outFile);
	void Load(std::ifstream& inFile);
};

void Drawing::Save(std::ofstream& outFile) {
	std::cout << "draw" << std::endl;
}

class ShapeFactory {
public:
	static ShapeFactory* Instance() {
		if(!pInstance_)
			pInstance_ = new ShapeFactory;
		return pInstance_;
	};

	typedef Shape* (*CreateShapeCallback)();//A pointer points to function.
private:
	typedef std::map<int, CreateShapeCallback> CallbackMap;
public:
	bool RegisterShape(int shapeId, CreateShapeCallback createFn);
	bool UnregisterShape(int shapeId);
	Shape* CreateShape(int shapeId);
private:
	ShapeFactory(){};
	//ShapeFactory(const ShapeFactory&);
	static ShapeFactory* pInstance_;
	CallbackMap callbacks_;
};

ShapeFactory* ShapeFactory::pInstance_ = 0;

bool ShapeFactory::RegisterShape(int shapeId, CreateShapeCallback createFn) {
	return callbacks_.insert(CallbackMap::value_type(shapeId, createFn)).second;
};

Shape* ShapeFactory::CreateShape(int shapeId) {
	CallbackMap::const_iterator i = callbacks_.find(shapeId);
	if(i == callbacks_.end()) {
		throw std::runtime_error("Unknown Shape ID");
	}
	return (i->second)();
}

bool ShapeFactory::UnregisterShape(int shapeId) {
	return callbacks_.erase(shapeId) == 1;
};

namespace {
	Shape* CreateLine() {
		return new Line;
	}
	const int line = 1;
	const bool registered = ShapeFactory::Instance()->RegisterShape(line, CreateLine); //TheShapeFactory is a singleton factory.
}

typedef void (*funcptr)(void); //Construct a function that don't have constent and return.


#else
//Do nothing.
#endif
